//
/**
 * Filename: fig10-22_sigsuspend1.c
 * Author:   csbonkers
 * Contact:  forever65535@qq.com
 * Date:     2021/6/19
 * Description:
 *    保护临界区代码不被特定信号中断
 */

#include "apue.h"

static void sig_int(int signo);

int main(int argc, char *argv[]) {
  pr_mask("program start: ");
  if ((c_signal(SIGINT, sig_int)) == SIG_ERR) {
    err_sys("signal(SIGINT) error");
  }
  sigset_t newmask, oldmask, waitmask;
  sigemptyset(&newmask);
  sigemptyset(&waitmask);
  sigaddset(&newmask, SIGINT);
  sigaddset(&waitmask, SIGUSR1);
  // block SIGINT and save current signal mask
  if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
    err_sys("SIG_BLOCK error");
  }

  /*
   * critical region of code.
   */

  pr_mask("in critical code: ");

  /*
   * pause, allowing all signals except SIGUSR1
   */
  if (sigsuspend(&waitmask)  != -1) {
    err_sys("sigsuspend error");
  }
  pr_mask("after return from sigsuspend: ");

  /*
   * reset signal mask which unblock SIGINT
   */
  if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
    err_sys("SIG_SETMASK error");
  }
  /*
   * And continue processing...
   */
  pr_mask("program exit: ");
  return 0;
}

static void sig_int(int signo) {
  pr_mask("\nin sig_oth: ");
}

// annotation:
//   sigsuspend()  temporarily  replaces the signal mask of the calling thread with
//   the mask given by mask and then suspends the thread until delivery of a signal
//   whose action is to invoke a signal handler or to terminate a process.
//
//   If  the  signal terminates the process, then sigsuspend() does not return.  If
//   the signal is caught, then sigsuspend() returns after the signal  handler  returns,
//   and the signal mask is restored to the state before the call to sigsuspend().